package com.gitee.liuzhi.microservice.minio.server.utils;

import com.gitee.liuzhi.framework.starter.response.exception.FileException;
import com.gitee.liuzhi.framework.starter.utils.AssertUtils;
import com.gitee.liuzhi.microservice.minio.server.properties.MinioProperties;
import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.http.MediaType;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Objects;
import java.util.Optional;

/**
 * Created by 2022/5/11/0011
 *
 * @author LiuZhi
 * @version V1.0
 * @description: Minio 工具类
 */
@Slf4j
public class MinioUtil {

    private static MinioClient minioClient;

    private static MinioProperties minioProperties;

    private static String bucketName;

    public MinioUtil() {
    }

    public static void setMinioClient(MinioClient minioClient) {
        MinioUtil.minioClient = minioClient;
    }

    public static void setMinioProperties(MinioProperties minioProperties) {
        MinioUtil.minioProperties = minioProperties;
    }

    public static void setBucketName(String bucketName) {
        MinioUtil.bucketName = bucketName;
    }

    /**
     * 上传文件
     *
     * @param file file
     * @return fileUrl
     */
    public static String uploadFile(MultipartFile file) {
        AssertUtils.isNull(file, "uploadFile file cannot null");
        AssertUtils.isNull(file.getOriginalFilename(),"uploadFile fileName cannot null");
        AssertUtils.isNull(file.getSize(),"uploadFile fileSize cannot null");
        log.info(String.format("uploadFile begin. fileName:[%s]. fileSize:[%s]byte", file.getOriginalFilename(), file.getSize()));
        try {
            InputStream inputStream = file.getInputStream();
            String fileName = analysisFileName(Objects.requireNonNull(file.getOriginalFilename()));
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(fileName)
                    .stream(inputStream, inputStream.available(), -1L)
                    .contentType(file.getContentType()).build();
            Optional.ofNullable(minioClient.putObject(putObjectArgs)).ifPresent(response ->
                    log.info(String.format("uploadFile success. bucketName:[%s]. objectName:[%s]", response.bucket(), response.object())));
            return analysisFileUrl(fileName);
        } catch (Exception e) {
            log.error(String.format("uploadFile fail. message : %s", e.getMessage()), e);
            throw new FileException("uploadFile fail.");
        }
    }

    /**
     * 删除文件
     *
     * @param fileUrl fileUrl
     */
    public static void deleteFile(String fileUrl) {
        AssertUtils.isNull(fileUrl, "deleteFile fileUrl cannot blank");
        log.info(String.format("deleteFile begin. fileUrl:[%s]", fileUrl));
        String[] split = fileUrl.split("/");
        fileUrl = split[split.length - 1];
        try {
            RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(bucketName).object(fileUrl).build();
            minioClient.removeObject(removeObjectArgs);
        } catch (Exception e) {
            log.error(String.format("deleteFile fail. message : %s", e.getMessage()), e);
            throw new FileException("deleteFile fail.");
        }
    }

    /**
     * 下载文件
     *
     * @param fileUrl  图片路径
     * @param fileName 下载后图片名称
     * @param response HttpServletResponse
     */
    public static void downloadFile(String fileUrl, String fileName, HttpServletResponse response) {
        AssertUtils.isNull(fileUrl, "deleteFile fileUrl cannot blank");
        log.info(String.format("downloadFile begin. fileUrl:[%s]. fileName:[%s]", fileUrl, fileName));
        if (StringUtils.isEmpty(fileName)) {
            fileName = fileUrl;
        }
        fileUrl = fileUrl.substring(fileUrl.indexOf(bucketName) + bucketName.length() + 1);
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + URLEncoder.encode(fileName, StandardCharsets.UTF_8));
        try {
            InputStream inputStream = minioClient.getObject(((GetObjectArgs.builder().bucket(bucketName)).object(fileUrl)).build());
            IOUtils.copy(inputStream, response.getOutputStream());
            inputStream.close();
        } catch (Exception e) {
            log.error(String.format("downloadFile fail. message : %s", e.getMessage()), e);
            throw new FileException("downloadFile fail.");
        }
    }

    private static String analysisFileUrl(String fileName) {
        return minioProperties.getPublicUrl() + "/" + minioProperties.getBucketName() + "/" + fileName;
    }

    private static String analysisFileName(String sourceName) {
        return DateFormatUtils.format(new Date(), "yyyyMMdd-HHmmss-SSS-") +
                (int) (Math.random() * 9000 + 1000) +
                "." +
                sourceName.split("\\.")[1];
    }


}
